
#include <iostream>
#include <string>
#include <ctime>
#include <cstring>
#include <unistd.h>

// =============== Windows ==============
#if defined(_WIN32) || defined(_WIN64)
#include <cstdint>
#include <ws2tcpip.h>
#include <winsock2.h>
#include "ws2ipdef.h"
#include <windows.h>
#pragma comment(lib, "ws2_32.lib")
#define close(sock) closesocket(sock)
typedef SOCKET socket_t;
#define INVALID_SOCKET_VALUE INVALID_SOCKET
using ushort = unsigned short;
// =========  Unix/Linux/Macos  =========
#else
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <ifaddrs.h> //ipv4
#include <netdb.h>   //ipv4
#include <sys/select.h>
#define INVALID_SOCKET_VALUE -1
typedef int             socket_t;
typedef struct sockaddr SOCKADDR;
#endif

#define BUFFER_SIZE 1024

// 编译： g++ -pthread udp_server.cpp -o udp_server.exe -lws2_32
int main(int argc, char *argv[]) {
	if (argc != 2) {
		std::cerr << "Usage: " << argv[0] << " <port>" << std::endl;
		return 1;
	}
	int                port = std::stoi(argv[1]);
	int                sockFd;
	struct sockaddr_in server, client;
	socklen_t          client_len = sizeof(client);
	char               buffer[BUFFER_SIZE];

	sockFd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (sockFd < 1) {
		std::cerr << "UDP socket creation failed!" << std::endl;
		return 1;
	}

	server.sin_family      = AF_INET;
	server.sin_port        = htons(port);
	server.sin_addr.s_addr = INADDR_ANY;
	if (bind(sockFd, (struct sockaddr *) &server, sizeof(server)) < 0) {
		std::cerr << "UDP bind failed!" << std::endl;
		close(sockFd);
		return 1;
	}
	std::cout << "UDP server running on " << port << "..." << std::endl;

	while (true) {
		memset(buffer, 0, BUFFER_SIZE);
		ssize_t received = recvfrom(sockFd, buffer, BUFFER_SIZE - 1, 0, (struct sockaddr *) &client, &client_len);
		if (received > 0) {
			buffer[received] = '\0';
			std::cout << "Received [" << inet_ntoa(client.sin_addr) << ":" << ntohs(client.sin_port) << "] \t " << buffer << std::endl;
			std::string response  = "Hello " + std::string(buffer);
			ssize_t     sentBytes = sendto(sockFd, response.c_str(), response.length(), 0, (struct sockaddr *) &client, client_len);
		}
	}
	close(sockFd);
	return 0;
}
